use util::RawData;
extern "C" {
    pub fn super_feature(p:*const libc::c_uchar,n:libc::c_int,sf:*mut SuperFeature);
    pub fn Finesse(p:*const libc::c_uchar,n:libc::c_int,sf:*mut SuperFeature);
}

#[derive(Clone, Copy,Debug)]
pub enum SuperFeatureMethod {
    SuperFeature,
    SuperFeatureAvx,
    SuperFeatureAvxFast,
    Finesse,
    FinesseAvx,
}

impl SuperFeatureMethod {
    pub fn is_smooth(&self) -> bool {
        false
    }
}


pub static mut SUPER_FEATURE_METHOD:SuperFeatureMethod = SuperFeatureMethod::SuperFeature;
pub fn super_feature_algorithm_acquire() -> SuperFeatureMethod {
    unsafe { SUPER_FEATURE_METHOD }
}

pub fn config_super_feature_algorithm(super_feature_method:&str) -> Result<(),String> {
    unsafe {
        SUPER_FEATURE_METHOD = match super_feature_method {
            "superfeature" => SuperFeatureMethod::SuperFeature,
            "superfeature-avx" => SuperFeatureMethod::SuperFeatureAvx,
            "superfeature-avx-fast" => SuperFeatureMethod::SuperFeatureAvxFast,
            "finesse" => SuperFeatureMethod::Finesse,
            "finesse-avx" => SuperFeatureMethod::FinesseAvx,
            _ => return Err(super_feature_method.to_string()),
        };
        Ok(())
    }
}

#[repr(C)]
#[derive(RawData,PartialEq)]
pub struct SuperFeature {
    feature:[u64;3]
}

impl SuperFeature {
    pub fn new() -> Self {
        Self {feature:[0;3]}
    }

    pub fn init(&mut self,data:&[u8]) {
        match super_feature_algorithm_acquire() {
            SuperFeatureMethod::SuperFeature => self.super_feature_init(data),
            SuperFeatureMethod::SuperFeatureAvx => self.super_feature_avx_init(data),
            SuperFeatureMethod::SuperFeatureAvxFast => self.super_feature_avx_fast_init(data),
            SuperFeatureMethod::Finesse => self.finesse_init(data),
            SuperFeatureMethod::FinesseAvx => self.finesse_avx_init(data),
        }
    }

    pub fn features(&self,_sf_num:usize) -> &[u64] {
        &self.feature
    }

    pub fn super_feature_init(&mut self,data:&[u8]) {
        unsafe {
            super_feature(&data[0] as *const libc::c_uchar, data.len().try_into().unwrap(), self);
        }
    }

    pub fn super_feature_avx_init(&mut self,data:&[u8]) {
        unsafe {
            super_feature(&data[0] as *const libc::c_uchar, data.len().try_into().unwrap(), self);
        }
    }

    pub fn super_feature_avx_fast_init(&mut self,data:&[u8]) {
        unsafe {
            super_feature(&data[0] as *const libc::c_uchar, data.len().try_into().unwrap(), self);
        }
    }

    pub fn finesse_init(&mut self,data:&[u8]) {
        unsafe { Finesse(&data[0] as *const libc::c_uchar, data.len().try_into().unwrap(), self); }
    }

    pub fn finesse_avx_init(&mut self,data:&[u8]) {  
        unsafe { Finesse(&data[0] as *const libc::c_uchar, data.len().try_into().unwrap(), self); }
    }

    pub fn test_gear_roll(&mut self,_data:&[u8]) -> usize {
        0
    }

    pub fn test_pack_feature(&mut self) {

    }
}